import click
import os
import platform
import sys
from collections import OrderedDict

import sh
from fastapi.routing import APIRoute
from common.database import SessionLocal
from sqlalchemy import create_engine

from app.auth.models import AuthPermissions
from main import app
from setting import config
from app.auth.script import auth_cli
from app.bill.script import bill_cli
from app.monitor_logs.script import monitor_log
from app.monitor_doris.script import monitor_doris
from app.service_quality.script import qos_alarm


class Ops(object):
    def __init__(self):
        self.root = os.path.dirname(os.path.abspath(__file__))
        self.alembic_dirname = os.path.join(self.root, 'alembic')
        self.alembic_ini = os.path.join(self.root, 'alembic.ini')
        self.alembic_env = os.path.join(self.alembic_dirname, 'env.py')

    def init(self):
        self.db_create()
        self.alembic_init()
        self.alembic_migrate()
        self.alembic_upgrade()
        self.db_import_data()

    @classmethod
    def platform_check(cls):
        if platform.system().lower() == 'window':
            click.echo('ops init must be execute linux platform')
            sys.exit(0)

    def directory_check(self):
        if os.path.exists(self.alembic_dirname):
            click.echo('alembic directory already exists')
            sys.exit(0)

    def alembic_init(self):
        self.platform_check()
        self.directory_check()
        output = sh.alembic(['init', 'alembic'], _cwd=self.root)
        if output.exit_code == 0:
            click.echo(output.stdout)
            click.echo(f'alembic init success')

        output = sh.sed(
            ['-ri', f's#^sqlalchemy.url.*$#sqlalchemy.url = {config.SQLALCHEMY_DATABASE_URI}\&binary_prefix=true#',
             self.alembic_ini])
        if output.exit_code == 0:
            click.echo(f'alembic.ini modify success')

        sh.sed(['-ri', 's/^target_metadata.*$/target_metadata = Base.metadata/', self.alembic_env])
        sh.sed(['-ri', '/^target_metadata/ i from common.database import Base', self.alembic_env])
        output = sh.sed(['-ri', '/^target_metadata/ i from app.auth.models import *', self.alembic_env])
        if output.exit_code == 0:
            click.echo(f'models auth mapping setting success')
        output = sh.sed(['-ri', '/^target_metadata/ i from app.monitor_logs.models import *', self.alembic_env])
        if output.exit_code == 0:
            click.echo(f'models monitor_logs mapping setting success')

        output = sh.sed(['-ri', '/^target_metadata/ i from app.monitor_doris.models import *', self.alembic_env])
        if output.exit_code == 0:
            click.echo(f'models monitor_doris mapping setting success')

        output = sh.sed(['-ri', '/^target_metadata/ i from app.manage_notice.models import *', self.alembic_env])
        if output.exit_code == 0:
            click.echo(f'models manage_notice mapping setting success')

        output = sh.sed(['-ri', '/^target_metadata/ i from app.notice_center.models import *', self.alembic_env])
        if output.exit_code == 0:
            click.echo(f'models notice_center mapping setting success')

        output = sh.sed(['-ri', '/^target_metadata/ i from app.bill.models import *', self.alembic_env])
        if output.exit_code == 0:
            click.echo(f'models bill mapping setting success')

        output = sh.sed(['-ri', '/^target_metadata/ i from app.tools_url_shorten.models import *', self.alembic_env])
        if output.exit_code == 0:
            click.echo(f'models tools_url_shorten mapping setting success')

        output = sh.sed(['-ri', '/^target_metadata/ i from app.tools_jumpserver.models import *', self.alembic_env])
        if output.exit_code == 0:
            click.echo(f'models tools_jumpserver mapping setting success')

        output = sh.sed(['-ri', '/^target_metadata/ i from app.celery_task.models import *', self.alembic_env])
        if output.exit_code == 0:
            click.echo(f'models celery_task mapping setting success')

        output = sh.sed(['-ri', '/^target_metadata/ i from app.audit.models import *', self.alembic_env])
        if output.exit_code == 0:
            click.echo(f'models audit mapping setting success')

        output = sh.sed(['-ri', '/^target_metadata/ i from app.expense_quota.models import *', self.alembic_env])
        if output.exit_code == 0:
            click.echo(f'models expense_quota mapping setting success')

        output = sh.sed(['-ri', '/^target_metadata/ i from app.service_quality.models import *', self.alembic_env])
        if output.exit_code == 0:
            click.echo(f'models service_quality mapping setting success')

        output = sh.sed(['-ri', '/^target_metadata/ i from app.bigdata.models import *', self.alembic_env])
        if output.exit_code == 0:
            click.echo(f'models target_metadata mapping setting success')

    def alembic_migrate(self):
        """
        自动生成迁移脚本
        """
        self.platform_check()
        output = sh.alembic(['revision', '--autogenerate'], _cwd=self.root)
        if output.exit_code == 0:
            click.echo(output.stderr)
            click.echo(f'alembic migrate success')

    def alembic_upgrade(self):
        """
        迁移脚本映射数据库
        :return:
        """
        self.platform_check()
        output = sh.alembic(['upgrade', 'head'], _cwd=self.root)
        if output.exit_code == 0:
            click.echo(output.stderr)
            click.echo('alembic upgrade success')

    @classmethod
    def db_create(cls):
        """
        创建数据库
        """
        engine = create_engine(
            f"mysql+pymysql://{config.MYSQL_USERNAME}:{config.MYSQL_PASSWORD}@{config.MYSQL_HOST}:{config.MYSQL_PORT}")

        with engine.connect() as conn:
            conn.execute("commit")
            conn.execute(
                f"CREATE DATABASE IF NOT EXISTS {config.MYSQL_DATABASE} DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci")
            try:
                engine.execute(f"USE {config.MYSQL_DATABASE}")
                click.echo('database create success')
            except Exception as db_exc:
                # logging.exception("Exception creating database: " + str(db_exc))
                click.echo("Exception creating database: " + str(db_exc))

    @classmethod
    def db_import_data(cls):
        """
        导入初始化数据
        """

        session = SessionLocal()
        for route in app.routes:
            if isinstance(route, APIRoute):
                if route.path in ["/ops/api/v1/login", "/ops/api/v1/user/info"]:
                    continue
                data = {"permission_name": route.name, "method": list(route.methods)[0].lower(),
                        "url": route.path, "tags": list(route.tags)[0].lower(),
                        "summary": route.summary, "description": route.description}
                AuthPermissions.saves(session, [data])
        session.close()
        return {"message": "ok!"}


@click.group()
def db_operation():
    pass


@db_operation.command()
def db_drop():
    """Command on cli2"""


@click.group()
def ops_operation():
    pass


@ops_operation.command()
def ops_init():
    """
    平台数据初始化
    """
    ops = Ops()
    ops.init()


@click.group()
def alembic_operation():
    pass


@alembic_operation.command()
def db_migrate():
    """
    迁移脚本生成
    """
    ops = Ops()
    ops.alembic_migrate()


@alembic_operation.command()
def db_upgrade():
    """
    迁移脚本映射数据库
    """
    ops = Ops()
    ops.alembic_upgrade()


cli = click.CommandCollection(sources=[ops_operation, alembic_operation, bill_cli, qos_alarm, auth_cli, monitor_doris])

if __name__ == '__main__':
    cli()
